// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
//
// Description: entropy_src health tests module
//

module entropy_src_shtests (
  input                  clk_i,
  input                  rst_ni,

   // ins req interface
  input logic            entropy_bit_i,
  input logic            entropy_bit_vld_i,
  input logic            rct_active_i,
  input logic [15:0]     rct_max_cnt_i,
  input logic            apt_active_i,
  input logic [15:0]     apt_max_cnt_i,
  input logic [15:0]     apt_window_i,
  output logic           rct_fail_pls_o,
  output logic           apt_fail_pls_o,
  output logic           shtests_passing_o
);

  // signals
  logic rct_samples_match;
  logic rct_fail;
  logic rct_pass;
  logic apt_reset_test;
  logic apt_samples_match;
  logic apt_fail;
  logic apt_pass;


  // flops
  logic        rct_prev_sample_q, rct_prev_sample_d;
  logic [15:0] rct_rep_cntr_q, rct_rep_cntr_d;
  logic        apt_initial_sample_q, apt_initial_sample_d;
  logic [15:0] apt_sample_cntr_q, apt_sample_cntr_d;
  logic [15:0] apt_match_cntr_q, apt_match_cntr_d;
  logic        rct_passing_q, rct_passing_d;
  logic        apt_passing_q, apt_passing_d;

  always_ff @(posedge clk_i or negedge rst_ni)
    if (!rst_ni) begin
      rct_prev_sample_q     <= '0;
      rct_rep_cntr_q        <= '0;
      apt_initial_sample_q  <= '0;
      apt_sample_cntr_q     <= '0;
      apt_match_cntr_q      <= '0;
      rct_passing_q    <= '0;
      apt_passing_q    <= '0;
    end else begin
      rct_prev_sample_q     <= rct_prev_sample_d;
      rct_rep_cntr_q        <= rct_rep_cntr_d;
      apt_initial_sample_q  <= apt_initial_sample_d;
      apt_sample_cntr_q     <= apt_sample_cntr_d;
      apt_match_cntr_q      <= apt_match_cntr_d;
      rct_passing_q    <= rct_passing_d;
      apt_passing_q    <= apt_passing_d;
    end



  // Repetition Count Test (RCT)
  //
  // Point of test
  //  check for back to back patterns up to a
  //  limit, fail if it does


  // NIST A sample
  assign rct_prev_sample_d = ~rct_active_i ? 1'b0 :
         (entropy_bit_vld_i & (rct_rep_cntr_q == 16'h0001)) ? entropy_bit_i :
         rct_prev_sample_q;

  assign rct_samples_match = (rct_prev_sample_q == (entropy_bit_vld_i & entropy_bit_i));

  // NIST B counter
  assign rct_rep_cntr_d =
         ~rct_active_i ? 16'h0001 :
         rct_fail ? 16'h0001 :
         (entropy_bit_vld_i & rct_samples_match) ? (rct_rep_cntr_q+1) :
         rct_pass ? 16'h0001 :
         rct_rep_cntr_q;

  assign rct_pass = rct_active_i & (entropy_bit_vld_i & ~rct_samples_match);
  assign rct_fail = rct_active_i & (rct_rep_cntr_q >= rct_max_cnt_i);
  assign rct_fail_pls_o = rct_fail;

  assign rct_passing_d =
         ~rct_active_i ? 1'b1 :
         rct_fail ? 1'b0 :
         rct_pass ? 1'b1 :
         rct_passing_q;


  // Adaptive Proportion Test (APT)
  //
  // Point of test
  //  sample once, then check for period of time if
  //  that pattern appears again, fail if it does


  // NIST N value
  assign apt_reset_test = ~apt_active_i | apt_fail | (apt_sample_cntr_q >= apt_window_i);

  // NIST A counter
  assign apt_initial_sample_d =
         ((apt_sample_cntr_q == 16'h0000) & entropy_bit_vld_i) ? entropy_bit_i :
         apt_initial_sample_q;

  // NIST S counter
  assign apt_sample_cntr_d = apt_reset_test ? 16'b0 :
         entropy_bit_vld_i ? (apt_sample_cntr_q+1) :
         apt_sample_cntr_q;

  assign apt_samples_match = entropy_bit_vld_i & (apt_initial_sample_q == entropy_bit_i);

  // NIST B counter
  assign apt_match_cntr_d = apt_reset_test ? 16'b0 :
         (entropy_bit_vld_i & apt_samples_match) ? (apt_match_cntr_q+1) :
         apt_match_cntr_q;

  assign apt_pass = (apt_sample_cntr_q >= apt_window_i);
  assign apt_fail = apt_active_i & (apt_match_cntr_q >= apt_max_cnt_i);
  assign apt_fail_pls_o = apt_fail;

  assign apt_passing_d =
         ~apt_active_i ? 1'b1 :
         apt_fail ? 1'b0 :
         apt_pass ? 1'b1 :
         apt_passing_q;

  // tests summary
  assign shtests_passing_o = rct_passing_q && apt_passing_q;

endmodule
